﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Microsoft.Forums.OfflineStore;
using System.Collections.ObjectModel;
using System.Data.Linq;
using System.Threading;
using System.Windows.Threading;
using Microsoft.Forums.SyncService;
using System.IO;

namespace Microsoft.Forums.ForumsClient.ThreadedView
{
    /// <summary>
    /// A container for a forum that will have its root posts displayed on the UI
    /// This wraps child posts in ObserableCollections
    /// </summary>
    public class ForumContainer : INotifyPropertyChanged
    {
        /// <summary>
        /// Connection string to connect to the database
        /// </summary>
        string connectionString;

        /// <summary>
        /// The dispatcher from the UI thread
        /// </summary>
        Dispatcher dispatcherUI;

        /// <summary>
        ///  Hold sync in progress state
        /// </summary>
        bool isSyncInProgress;

        /// <summary>
        /// The forum for this forum container
        /// </summary>
        public Forum Forum
        {
            get;
            private set;
        }

        /// <summary>
        /// Event to notify listeners when a call to PopulateRootPosts has completed
        /// </summary>
        public event EventHandler PopulateRootsCompleted;

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Fired when certain properties change
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        /// <summary>
        /// The collection of root posts for the forum
        /// </summary>
        public DispatchingObservableCollection<PostContainer> RootPosts
        {
            get;
            private set;
        }

        /// <summary>
        /// The number of unread posts
        /// </summary>
        public int UnreadPostCount
        {
            get;
            private set;
        }

        /// <summary>
        ///  Get / Set Synchronization in progress for the forum represented by this forumcontainer 
        /// </summary>
        public bool IsSyncInProgress
        {
            get
            {
                return isSyncInProgress;
            }
            set
            {
                isSyncInProgress = value;
                OnPropertyChanged("IsSyncInProgress");
            }
        }

        /// <summary>
        /// Create a forum container for the given forum.
        /// 
        /// Pre-Condition: Must be created on the UI Thread
        /// </summary>
        /// <param name="forumId">forum to make container for</param>
        /// <param name="connection">Connection string to database</param>
        public ForumContainer(Forum forum, string connection)
        {
            if (forum == null) throw new ArgumentNullException("forum", "forum must not be null");

            dispatcherUI = Dispatcher.CurrentDispatcher;
            Forum = forum;
            connectionString = connection;
            RootPosts = new DispatchingObservableCollection<PostContainer>(dispatcherUI);

        }

        /// <summary>
        /// Refresh all the root posts for this forum.  This also clear all child posts that may have been loaded.
        /// </summary>
        public void PopulateRootPosts()
        {
            RootPosts.Clear();

            ThreadPool.QueueUserWorkItem(
                     delegate
                     {
                         using (var store = new ForumsOfflineStore(connectionString))
                         {
                             DataLoadOptions dlo = new DataLoadOptions();
                             // Ensure the foreign key objects get loaded
                             dlo.LoadWith<Post>(p => p.PostPropertySet);
                             dlo.LoadWith<Post>(p => p.CreatedBy);
                             store.LoadOptions = dlo;

                             var forum = store.Forums.Single(f => f.Id == Forum.Id);
                             foreach (var thread in forum.Threads)
                             {
                                 var rootPosts = thread.Posts.Where(p => p.ParentId == null);
                                 foreach (var p in rootPosts)
                                 {
                                     RootPosts.Add(new PostContainer(p, connectionString, dispatcherUI));
                                 }
                             }

                         }

                         OnPopulateRootsCompleted();
                     });
        }


        /// <summary>
        /// Refreshed the unread and total counts directly from the database
        /// </summary>
        public void RefreshPostCounts()
        {
            using (var store = new ForumsOfflineStore(connectionString))
            {
                UnreadPostCount = store.Posts.Count(p => p.Thread.ForumId == Forum.Id && p.PostPropertySet.IsRead == false);
                OnPropertyChanged("UnReadPostCount");
            }
        }

        /// <summary>
        /// Marks a given post as read and updates the Forum's unread post count
        /// </summary>
        /// <param name="post">The post to mark as read</param>
        public void MarkPostAsRead(PostContainer post)
        {
            if (!post.Post.PostPropertySet.IsRead)
            {
                UnreadPostCount--;
                post.MarkAsRead();
                OnPropertyChanged("UnReadPostCount");
            }
        }

        /// <summary>
        /// Populates the child posts of the given post
        /// </summary>
        /// <param name="post">Post to populate children of</param>
        public void PopulateChildPosts(PostContainer post)
        {
            post.PopulateChildPosts();
        }

        /// <summary>
        /// Clears the child posts of the given post
        /// </summary>
        /// <param name="post">Post to clear the children of</param>
        public void ClearChildPosts(PostContainer post)
        {
            post.ClearChildPosts();
        }

        /// <summary>
        /// Fires the populate complete event if anyone is listening to it
        /// </summary>
        private void OnPopulateRootsCompleted()
        {
            if (PopulateRootsCompleted != null)
            {
                PopulateRootsCompleted(this, new EventArgs());
            }
        }


        /// <summary>
        /// Fire the property changed event for the given property name
        /// </summary>
        /// <param name="propertyName">Name of the property</param>
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}
